package cz.jm.web.manhunter.server.services;

import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

import cz.jm.util.logging.LoggerClassPathConfigurator;
import cz.jm.web.manhunter.client.services.UserDataService;
import cz.jm.web.manhunter.server.MailSender;
import cz.jm.web.manhunter.server.authentication.Account;
import cz.jm.web.manhunter.server.authentication.Authentication;
import cz.jm.web.manhunter.shared.User;
import cz.jm.web.manhunter.shared.User.UserState;

@SuppressWarnings("serial")
public class UserDataServiceImpl extends RemoteServiceServlet 
	implements UserDataService {

	private static SessionFactory factory;
	private static LoggerClassPathConfigurator loggerConfigurator = new LoggerClassPathConfigurator();
	private static Logger log = Logger.getLogger(UserDataServiceImpl.class.getName());
	static {
		try {
			loggerConfigurator.configure();
			
			log.config("init of hibernate session factory - start");
			
			Configuration configuration = new Configuration().configure();
			ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().
					applySettings(configuration.getProperties()).buildServiceRegistry();		
			factory = configuration.buildSessionFactory(serviceRegistry);
			
			log.config("init of hibernate session factory - done");
			
		}
		catch (HibernateException e) {
			System.out.print(e.getMessage());
		}
	}
			
	
	
	@Override
    public User authenticateUser(String userToken)
            throws IllegalArgumentException {

		User user = new User();
		
//		Session session = factory.openSession();
//		try {
//			long id = Long.parseLong(userToken);
//			
//			Transaction tr = session.beginTransaction();
//			
//			user = (User) session.get(User.class, id);			
//			
//			if (user == null) {
//				user = new User();
//				user.setText("New user!");
//			}
//			else {
//				user.setText(user.getText()+ " Old user!");
//			}			
//			session.saveOrUpdate(user);
//			
//			tr.commit();
//		}
//		catch (Throwable e) {
//			
//		}
//		finally {
//			session.close();
//		}
		
		return user;
    }

	
	@Override    
	public User authenticateUser(String userIdentification, String password)  
			throws IllegalArgumentException {

		User result = new User();

		Session session = factory.openSession();
		try {
			
			
			Transaction tr = session.beginTransaction();
			
			Query userAuthenticationQuery = session.createQuery("from Authentication where account.username = ? or account.mail = ?");
			userAuthenticationQuery.setString(0, userIdentification);
			userAuthenticationQuery.setString(1, userIdentification);
			
			Authentication a = (Authentication)userAuthenticationQuery.uniqueResult();
						
			if (a != null) {
				// Ucet uzivatela bol identifikovany.
				if (a.getPassword().equals(password)) {
					 // Zadane heslo zodpoveda identifikovanemu uctu.
					if (a.getAccount().getDeleteDate() != null) {
						// Ucet vsak bol zmazany.
						result.setState(UserState.AUTHENTICATION_FAILED);
					}
					else if (a.getAccount().getVerificationDate() == null) {
						// Ucet este nebol overeny emailom.
						result.setState(UserState.REGISTERED_UNVERIFIED);
					}
					else {
						// Vsetko je OK takze nastavim ziskane vlastnosti uzivatela.
						result.setState(UserState.OK);
						a.getAccount().initUser(result);						
					}					
				}
				else {
					// Zadane nespravne heslo.
					result.setState(UserState.AUTHENTICATION_FAILED);
				}
				
				a.getAccount().setLastAccessDate(new Date());
				session.update(a.getAccount());
			}
			else {
				// Uzivatelsky ucet so zadanymi parametrami sa nepodarilo identifikovat - neexistuje.
				result.setState(UserState.AUTHENTICATION_FAILED);
			}
			
			tr.commit();
		}
		catch (Throwable e) {
			result.setState(UserState.ERROR);
		}
		finally {
			session.close();
		}
		
		return result;
	}

	
	@Override
    public User registerUser(User user, String password) throws IllegalArgumentException {
		
		// Prazdnny user - defaultne ID znaci ze sa prihlasenie nepodarilo.		
		Session session = factory.openSession();
		Transaction tr = session.beginTransaction();
		try {
			
			Query q = session.createQuery("from Account where username = ? or mail = ?");
			q.setString(0, user.getUsername());
			q.setString(1, user.getMail());
			
			List<Account> conflictAccounts = q.list(); 
			// Uzivatelske meno a ani heslo este nie je pouzite.
			if (conflictAccounts.isEmpty()) {
				
				Account account = new Account(user);
				session.save(account);
				
				Authentication sa = new Authentication(account, password);			
				session.save(sa);
				
				tr.commit();
				
				MailSender.sendRegistrationMail(account);
				
				user.setId(account.getId());
				user.setState(UserState.OK);
			}
			else {
				for (Account u : conflictAccounts) {
					
					if (u.getUsername().equals(user.getUsername())) {
						if (u.getMail().equals(user.getMail())) {
							user.setState(UserState.USERNAME_AND_MAIL_ALREADY_EXISTS);
						}
						else {
							user.setState(UserState.USERNAME_ALREADY_EXISTS);
						}
					}
					else if (u.getMail().equals(user.getMail())) {
						user.setState(UserState.MAIL_ALREADY_EXISTS);
					}
				}
			}
			

		}
		catch (Throwable e) {
			tr.rollback();
			user.setState(UserState.ERROR);
			e.printStackTrace();			
		}
		finally {
			session.close();
		}
		
		return user;
    }


	@Override
    public void confirmUserRegistration(long userId, String registrationKey) throws IllegalArgumentException {	  
		// Prazdnny user - defaultne ID znaci ze sa prihlasenie nepodarilo.		
		Session session = factory.openSession();
		Transaction tr = session.beginTransaction();
		try {
			
			Query q = session.createQuery("from Account where id = ?");
			q.setLong(0, userId);
			
			
			Account account = (Account)q.uniqueResult(); 
			// Uzivatelske meno a ani heslo este nie je pouzite.
			if (account != null) {
				
				account.setLastAccessDate(new Date());
				account.setVerificationDate(new Date());
				
				session.update(account);

				tr.commit();
				
			}
			// Nebudem osetrovat nic sa nedeje.
			//else { }
			

		}
		catch (Throwable e) {
			tr.rollback();
			e.printStackTrace();			
		}
		finally {
			session.close();
		}
		    
    }
}
